//
//  PECloudAPI.swift
//  PDFelement
//
//  Created by yegz on 2022/4/14.
//  Copyright © 2022 Wondershare. All rights reserved.
//

import Moya
import Foundation

public enum WSCloudService {

    public static let provider = MoyaProvider<WSCloudService>(plugins: [WSCloudPlugin()])

    case fileList(path: String)
    case fileRename(fileID: String, name: String)
    case directoryRename(fileID: String, name: String)
    case directoryCreate(path: String, name: String)
    case fileDelete(fileID: String)
    case copyFile(fileID: String, path: String, newName: String)
    case directoryDelete(fileID: String)
    case fileMove(fileID: String, path: String)
    case directoryMove(fileID: String, path: String)
    case getDownloadAddress(fileID: String)
    case downloadFile(url: URL, destURL: URL)
    case getUploadAddress(parameters: [String: Any])
    case uploadFile(url: URL, callback: String, fileURL: URL)
    case fetchOpacity

}

extension WSCloudService: TargetType {

    public var headers: [String: String]? {
        var header = [
            "token": "AccountManager.shared.getToken()",
            "authorization": "Basic NzkwOTgyOWIwZGViNmQ1M2NhM2MzZWEyNzg4Y2E4NDI6ZjljNTdjYWY3OTUzYmU5MDExOTRiN2I3M2UwMDNhN2M=",
            "Content-Type": "application/json",
            "ver": "2.0.4"
        ]
        switch self {
        case .downloadFile(_, _):
            header.removeValue(forKey: "Content-Type")
        case let .uploadFile(_, callback, _):
            header = ["Content-Type": "", "x-oss-callback": callback]
        default:
            break
        }
        return header
    }

    public var baseURL: URL {
        switch self {
        case .downloadFile(let url, _):
            return url
        case .uploadFile(let url, _, _):
            return url
        default:
            return URL(string: "https://api.pdfelement.io")!
        }
    }

    public var path: String {
        switch self {
        case .fileList(_):                                  return "/v2/file/directory/get-directory-children"
        case .fileRename(_, _):                             return "/v2/file/file/update-file-name"
        case .directoryRename(_, _):                        return "/v2/file/directory/update-directory-name"
        case .directoryCreate(_, _):                        return "/v2/file/directory/create-directory"
        case .fileDelete(_):                                return "/v2/file/file/delete-file"
        case .directoryDelete(_):                           return "/v2/file/directory/delete-directory"
        case .fileMove(_, _):                               return "/v2/file/file/update-file-path"
        case .directoryMove(_, _):                          return "/v2/file/directory/update-directory-path"
        case .getDownloadAddress(let fileID):               return "/v2/file/download/get-file-download-url/\(fileID)"
        case .copyFile(_, _, _):                            return "/v2/file/file/copy-file"
        case .getUploadAddress(_):                          return "/v2/file/file/oss-create-file"
        case .fetchOpacity:                                 return "/v2/user/base/get-user-capacity"
        case .downloadFile(_, _), .uploadFile(_, _, _):     return ""
        }
    }

    public var method: Moya.Method {
        switch self {
        case .fileList(_):             return .get
        case .fileRename(_, _):        return .post
        case .directoryRename(_, _):   return .post
        case .directoryCreate(_, _):   return .put
        case .fileDelete(_):           return .delete
        case .directoryDelete(_):      return .post
        case .fileMove(_, _):          return .post
        case .directoryMove(_, _):     return .post
        case .getDownloadAddress(_):   return .get
        case .downloadFile(_, _):      return .get
        case .copyFile(_, _, _):       return .post
        case .getUploadAddress(_):     return .put
        case .uploadFile(_, _, _):     return .put
        case .fetchOpacity:            return .get
        }
    }

    public var task: Task {
        var parameters: [String: Any] = [:]
        var encoding: ParameterEncoding = JSONEncoding.default
        switch self {
        case let .fileList(path):
            parameters = ["path": path, "page": 1, "page_size": 100, "get_total": true]
            encoding = URLEncoding.queryString
        case let .fileRename(fileID, name):
            parameters = ["new_name": name, "file_id": fileID]
        case let .directoryRename(fileID, name):
            parameters = ["new_name": name, "did": Int(fileID) ?? 0]
        case let .directoryCreate(path, name):
            parameters = ["path": path, "name": name]
        case let .fileDelete(fileID):
            parameters = ["file_id": fileID]
        case let .directoryDelete(fileID):
            parameters = ["did": Int(fileID) ?? 0]
        case let .fileMove(fileID, path):
            parameters = ["file_id": fileID, "path": path]
        case let .directoryMove(fileID, path):
            parameters = ["did": Int(fileID) ?? 0, "path": path]
        case let .copyFile(fileID, path, newName):
            parameters = ["file_id": fileID, "path": path, "new_name": newName, "replace": false]
        case .getDownloadAddress(_):
            encoding = URLEncoding.queryString
        case let .getUploadAddress(param):
            parameters = param
        case .fetchOpacity:
            encoding = URLEncoding.queryString
        case .downloadFile(_, let destURL):
            return .downloadDestination { _, _ in
                return (destURL, [])
            }
        case .uploadFile(_, _, let url):
            return .uploadFile(url)
        }
        return .requestParameters(parameters: parameters, encoding: encoding)
    }

    public var sampleData: Data {
        return "Half measures are as bad as nothing at all.".data(using: .utf8)!
    }

}

final class WSCloudPlugin: PluginType {

    func process(_ result: Result<Response, MoyaError>, target: TargetType) -> Result<Response, MoyaError> {
        guard let response = try? result.get(), let resp = WSCloudResponse<String>.map(response), resp.status != 200, resp.status != 4200 else { return result }

        var errorCode = 0
        if CloudCustomCode.allCases.contains(where: { $0.rawValue == resp.status }) {
            errorCode = resp.status
        } else {
            errorCode = CloudCustomCode.defaultCode.rawValue
        }

        guard let customCode = CloudCustomCode(rawValue: errorCode) else { return result }
        if customCode == .tokenExpire {
            print("tokenExpire")
//            Broadcaster.notify(WSCloudManagerProtocol.self) {
//                $0.tokenDidExpire()
//            }
        }
        let newResponse = Response(statusCode: customCode.rawValue, data: response.data)
        let error = MoyaError.statusCode(newResponse)
        return .failure(error)
    }

}

public enum CloudCustomCode: Int, CaseIterable {

    case tokenExpire = 1408
    case nameExists = 4002
    case parameterError = 2403
    case outOfCapacity = 4403
    case defaultCode = 5000000
    // 文件存在，直接显示成功
//    case fileExists = 4200

}
